在介紹完 runnable 組件和 Langchain 的 chain 設計之後,接著就要來介紹 LCEL 的核心概念,也就是串接這些組件的方式,我們先用簡表呈現:
工具名稱 | 描述 |
---|---|
RunnableSequence | 依序執行多個任務,前一個任務的輸出作為下個任務的輸入。 |
RunnableParallel | 並行執行多個任務,並返回每個任務的結果。 |
RunnableBranch | 根據條件選擇要執行的任務,當所有條件都不成立時,執行預設的任務。 |
RunnablePassthrough | 保留輸入不變,可同時對輸入進行額外處理的場景 |
前天的示範就是一個最簡單的案例,先將 SI Dream Engineering
傳遞到 prompt
當中,再給 LLM
。
from langchain_mistralai import ChatMistralAI
from langchain.prompts import ChatPromptTemplate
llm = ChatMistralAI(model="mistral-large-latest")
prompt = ChatPromptTemplate.from_template("Tell me a joke about {topic}")
chain = prompt | llm
chain.invoke({"topic":"SI Dream Engineering"})
RunnableParallel 則是將相同的 input 放到多個 chain,同時生成答案,以下的範例有沒有昨天 MultiQuery 的感覺?
from langchain.prompts import PromptTemplate
from langchain_mistralai import ChatMistralAI
from langchain_core.runnables import RunnableParallel
original_query = PromptTemplate(template="Answer this question: '{query}'")
new_query = PromptTemplate(template="Generate a different version of this question and answer: '{query}'")
llm = ChatMistralAI(model="mistral-large-latest")
parallel_queries = RunnableParallel({
"original_answer": original_query | llm,
"new_question_answer": new_query | llm,
})
result = parallel_queries.invoke({"query": "Tell me a story about SI Dream Engineering."})
print(result)
RunnableBranch 的使用場景則是可以設定條件,並將 input 導到執行不同任務,如下就是一個簡單的 router retriever 的應用場景。
retriever_law_db = ...
retriever_news_db = ...
retriever_db = ...
retriever_branch = RunnableBranch(
(lambda x: "law" in x["query"], retriever_law_db), # 如果 "law" 在 query 中
(lambda x: "news" in x["query"], retriever_news_db), # 如果 "news" 在 query 中
retriever_db # 否則執行 retriever_db
)
而 RunnablePassthrough 則是可以保留 input 原貌並往下傳遞給後續的任務,以下方語法為例,不僅保留了原始問題,並將其與檢索到的文件一起傳遞給 LLM 處理,相當於一個簡單版本的 RAG。
from langchain.prompts import PromptTemplate
from langchain_mistralai import ChatMistralAI
llm = ChatMistralAI(model="mistral-large-latest")
prompt = PromptTemplate(template="Given the document {doc}, please answer: {query}")
retriever = ...
retrieve_chain = RunnableParallel(
query=RunnablePassthrough(),
doc=retriever
) | prompt | llm
result = retrieve_chain.invoke({"query": "Tell me a story about SI Dream Engineering."})
print(result)
以 RunnableParallel
案例為例,我們可以透過 chain.get_graph().print_ascii()
查看目前 chain 的設計架構,也可以透過 chain.input_schema.schema()
、chain.output_schema.schema()
幫助檢視 chain 輸入與輸出資訊,幫助開發過程。
+----------------------------------------------------+
| Parallel<original_answer,new_question_answer>Input |
+----------------------------------------------------+
*** ***
*** ***
** **
+----------------+ +----------------+
| PromptTemplate | | PromptTemplate |
+----------------+ +----------------+
* *
* *
* *
+---------------+ +---------------+
| ChatMistralAI | | ChatMistralAI |
+---------------+ +---------------+
*** ***
*** ***
** **
+-----------------------------------------------------+
| Parallel<original_answer,new_question_answer>Output |
+-----------------------------------------------------+
ref.